package com.yuyou.fn.educational.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.wens.mybatisplus.examples.Example;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.service.ISiteConfigService;
import com.yuyou.fn.common.util.*;
import com.yuyou.fn.educational.entity.ExternalRegDetail;
import com.yuyou.fn.educational.entity.StudentReg;
import com.yuyou.fn.educational.service.IExternalRegDetailService;
import com.yuyou.fn.educational.service.IStudentRegService;
import com.yuyou.fn.educational.service.IThirdpartyDiscountCodeService;
import com.yuyou.fn.educational.vo.ThirdpartyDiscountCodeVo;
import okhttp3.*;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

@Service
public class ThirdpartyDiscountCodeServiceImpl implements IThirdpartyDiscountCodeService{

    private final Logger log = LoggerFactory.getLogger(ThirdpartyDiscountCodeServiceImpl.class);

    private OkHttpClient okHttpClient = OkHttpClientUtils.getIgnoreSsLClient(10,10 );

    @Value("${dev.env}")
    private boolean dev;

    @Resource
    private RedisTemplate<String,String> redisTemplate;


    @Resource
    private ISiteConfigService siteConfigService;

    @Resource
    private IStudentRegService studentRegService;

    @Resource
    private IExternalRegDetailService externalRegDetailService;


    public String getServiceBaseUrl() {
        String value = siteConfigService.getConfigValueFromCache("thirdparty-discount-code-base-url");
        if(dev && !value.contains("test")){
            throw new IllegalStateException("Invalid config");
        }
        return value;
    }

    public String getAppSecret() {
        return siteConfigService.getConfigValueFromCache("thirdparty-discount-code-appSecret");
    }

    public String getAppId() {
        return siteConfigService.getConfigValueFromCache("thirdparty-discount-code-appId");
    }

    @Override
    public ThirdpartyDiscountCodeVo checkCode(Long courseOrderId , BigDecimal orderPayableAmount, String discountCode,Long studentId , String studentName, String studentNo) {

        if(isLock( courseOrderId, discountCode) ){
            throw new BusException("此优惠码暂时锁定，请稍后再试");
        }
        return query(discountCode, studentId, studentName, studentNo ,orderPayableAmount );
    }

    public ThirdpartyDiscountCodeVo query( String discountCode, Long studentId, String studentName, String studentNo ,BigDecimal orderPayableAmount ) {
        String salt  = SignatureUtil.generateSalt(16);
        Long ts  = System.currentTimeMillis();

        StringBuilder params = new StringBuilder(100);
        params.append("couponCodes=").append(discountCode);
        params.append("&studentCode=").append(studentNo);
        params.append("&studentName=").append(studentName);
        params.append("&systemType=").append(getAppId());
        params.append("&ts=").append(ts );
        params.append("&signature=").append(SignatureUtil.generateRemoteSignature(salt,SignatureUtil.generateLocalSignature(Arrays.asList(discountCode,studentName,studentNo) , getAppId(),getAppSecret(),ts,salt)));


        Request request = new Request.Builder().url(getServiceBaseUrl() + "/coupon/info?" + params.toString() ).addHeader("Connection","close").get().build();
        Call call = okHttpClient.newCall(request);

        JSONObject ret  = null ;

        Response response = null;
        try {
            response = call.execute();

            if(!response.isSuccessful()){
                log.info("[优惠查询返回结果]status:{},message:{}",response.code(),response.message() );
            }
            String retStr  = response.body().string();
            log.info("[优惠查询返回结果]" + retStr);
            ret = JSONObject.parseObject(retStr);
        } catch (IOException e) {
            throw new BusException("电子优惠券系统服务出错",e );
        }finally {
            if(response != null ){
                response.close();
            }
        }

        if( ret.getIntValue("status") != 200 ){
            throw new BusException(ret.getString("description"));
        }
        JSONArray data = ret.getJSONArray("data");
        if(data == null || data.isEmpty() ){
            throw new BusException("优惠券出错");
        }
        ThirdpartyDiscountCodeVo thirdpartyDiscountCodeVo = data.getJSONObject(0).toJavaObject(ThirdpartyDiscountCodeVo.class);
        valid(thirdpartyDiscountCodeVo ,orderPayableAmount,studentId);
        return thirdpartyDiscountCodeVo;
    }

    @Override
    public List<ThirdpartyDiscountCodeVo> queryList(String phoneNo, String studentName, String studentNo) {
        String salt  = SignatureUtil.generateSalt(16);
        Long ts  = System.currentTimeMillis();

        StringBuilder params = new StringBuilder(100);
        //params.append("phone=").append(phoneNo);
        params.append("&studentName=").append(studentName);
        params.append("&studentCode=").append(studentNo);
        params.append("&systemType=").append(getAppId());
        params.append("&ts=").append(ts );
        params.append("&signature=").append(SignatureUtil.generateRemoteSignature(salt,SignatureUtil.generateLocalSignature(Arrays.asList(phoneNo,studentName,studentNo) , getAppId(),getAppSecret(),ts,salt)));


        Request request = new Request.Builder().url(getServiceBaseUrl() + "/coupon/list/"+phoneNo+"?" + params.toString() ).addHeader("Connection","close").get().build();
        Call call = okHttpClient.newCall(request);

        JSONObject ret  = null ;

        Response response = null;
        try {
            response = call.execute();

            if(!response.isSuccessful()){
                log.info("[优惠查询返回结果]status:{},message:{}",response.code(),response.message() );
            }
            String retStr  = response.body().string();
            log.info("[优惠查询返回结果]" + retStr);
            ret = JSONObject.parseObject(retStr);
        } catch (IOException e) {
            throw new BusException("电子优惠券系统服务出错",e );
        }finally {
            if(response != null ){
                response.close();
            }
        }

        if( ret.getIntValue("status") != 200 ){
            throw new BusException(ret.getString("description"));
        }
        JSONArray data = ret.getJSONArray("data");

        return data.toJavaList(ThirdpartyDiscountCodeVo.class);
    }

    @Override
    public void updateUsedStatus(Long courseOrderId, BigDecimal orderTotalAmount, String discountCode, BigDecimal discountAmount, String studentName, String studentNo,String version) {

        unlock(discountCode);

        if(version == null ){
            version = "1";
        }

        String salt  = SignatureUtil.generateSalt(16);
        Long ts  = System.currentTimeMillis();

        String couponCode = new JSONObject().fluentPut("couponCode", discountCode).fluentPut("version", version).toJSONString();
        couponCode = "["+couponCode+"]";
        String order = new JSONObject().fluentPut("bizOrderId", courseOrderId).fluentPut("orderAmount", orderTotalAmount).fluentPut("discountAmount" , discountAmount ).toJSONString();

        RequestBody body = new FormBody.Builder()
                .add("couponCode", couponCode)
                .add("studentName", studentName)
                .add("studentCode", studentNo)
                .add("order", order)
                .add("systemType", getAppId())
                .add("ts", String.valueOf(ts))
                .add("signature", SignatureUtil.generateRemoteSignature(salt,SignatureUtil.generateLocalSignature(Arrays.asList(couponCode,studentName,studentNo) , getAppId(),getAppSecret(),ts,salt)))
                .build();

        Request request = new Request.Builder().url(getServiceBaseUrl() + "/coupon/consume").post(body).build();
        Call call = okHttpClient.newCall(request);

        JSONObject ret  = null ;
        Response response = null;
        try {
            response = call.execute();
            String retStr  = response.body().string();
            log.info("[优惠更新返回结果]" + retStr);
            ret = JSONObject.parseObject(retStr);
        } catch (IOException e) {
            throw new BusException("电子优惠券系统服务出错",e );
        }finally {
            if(response != null ){
                response.close();
            }
        }

        if( ret.getIntValue("status") != 200 ){
            throw new BusException(ret.getString("description"));
        }

    }

    private void valid(ThirdpartyDiscountCodeVo thirdpartyDiscountCodeVo, BigDecimal orderPayableAmount, Long studentId) {
        if(thirdpartyDiscountCodeVo.getStatus() != 0 ){
            throw new BusException("优惠码已使用或过期");
        }

        if(thirdpartyDiscountCodeVo.getBeginDate().after(TimeUtils.now()) || DateUtils.addDays(thirdpartyDiscountCodeVo.getEndDate(),1).before(TimeUtils.now())){
            throw new BusException("优惠活动未开始或已经过期");
        }

        if(  thirdpartyDiscountCodeVo.getDiscountType() == 1 && orderPayableAmount != null && BigDecimals.compare(orderPayableAmount,thirdpartyDiscountCodeVo.getDiscountRequireAmount()) < 0 ){
            throw new BusException("订单金额不满足优惠要求");
        }

        if(thirdpartyDiscountCodeVo.getForNew() == 0 && !isOldStudent(studentId)){
            throw new BusException("仅旧生可用");
        }

        if(thirdpartyDiscountCodeVo.getForNew() == 1 && isOldStudent(studentId)){
            throw new BusException("仅新生可用");
        }
    }


    private boolean isLock(Long courseOrderId,String discountCode) {
        String lockCourseOrderId = (String)redisTemplate.opsForHash().get("thirdparty_code_lock", discountCode);
        if(lockCourseOrderId != null && !lockCourseOrderId.equals(String.valueOf(courseOrderId))){
            return true ;
        }
        return false ;

    }

    @Override
    public void lock(Long courseOrderId,String discountCode) {
        redisTemplate.opsForHash().put("thirdparty_code_lock", discountCode,String.valueOf(courseOrderId));
    }

    @Override
    public void unlock(String discountCode) {
        redisTemplate.opsForHash().delete("thirdparty_code_lock",discountCode);
    }

    public boolean isOldStudent(Long studentId) {

        Example<StudentReg> example = StudentReg.createExample();
        example.createCriteria().andEqualTo("studentId", studentId).andEqualTo("regStatus", 0).andEqualTo("chargingStatus" ,2 );
        long l = studentRegService.countByExample(example);
        if (l > 0) {
            return true;
        }

        Example<ExternalRegDetail> externalRegDetailExample = ExternalRegDetail.createExample();
        externalRegDetailExample.createCriteria().andEqualTo("studentId", studentId).andEqualTo("regStatus", 0);
        return externalRegDetailService.countByExample(externalRegDetailExample) > 0;

    }
}
